package edu.ccut.saturn.component.loader.node;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.dom4j.Element;
import org.osgi.framework.Bundle;

import edu.ccut.saturn.component.ComponentFactory;
import edu.ccut.saturn.component.ILogger;
import edu.ccut.saturn.component.INodeInfo;
import edu.ccut.saturn.component.IParameterInfo;
import edu.ccut.saturn.component.IValidateUseInfo;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.SaturnLoggerManager;
import edu.ccut.saturn.component.impl.SaturnParameterInfo;
import edu.ccut.saturn.component.loader.INodeLoader;
import edu.ccut.saturn.component.utils.LoaderUtils;

/**
 * 读取不同类型节点信息的抽象类,并实现读取参数信息功能.
 * <p>
 * 所有读取节点的实现类应该继承<code>NodeInfoLoader</code>, 并通过重写loadNode方法来实现对节点信息的读取.
 * 
 * @author 谷钰
 * @author 温建
 * 
 * @version 1.0, 2008.8.13
 * 
 * @see IParameterInfo
 * @see INodeInfo
 */
public abstract class NodeInfoLoader implements INodeLoader {

	public static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(SaturnLoggerManager.LOGGER_KEY_LOAD_BUNDLE);

	public static final String KEY_NODE_ID = "id";

	public static final String KEY_NODE_X = "x";

	public static final String KEY_NODE_Y = "y";

	public static final String KEY_NODE_NEXT = "next";

	public static final String KEY_NODE_NAME = "name";

	public static final String KEY_NODE_DESCRIPTION = "description";

	public static final String KEY_NODE_KEY = "key";

	public static final String KEY_NODE_EXCEPTION = "exception";

	public static final String KEY_PARAMETER_LIST = "parameters";

	public static final String KEY_PARAMETER = "parameter";

	public static final String KEY_PARAMETER_ID = "id";

	public static final String KEY_PARAMETER_NAME = "name";

	public static final String KEY_PARAMETER_CLASS_TYPE = "classType";

	public static final String KEY_PARAMETER_PASSING_TYPE = "passingType";

	public static final String KEY_PARAMETER_VALUE_KEY = "value-key";

	public static final String KEY_PARAMETER_DECRRIPTION = "description";

	public static final String KEY_PARAMETER_SCOPE = "scope";

	public static final String KEY_PARAMETER_VALIDATEUSE = "validates";

	/**
	 * 读取节点的参数列表信息
	 * 
	 * @param bundle
	 *            利用bundle加载class
	 * @param node
	 *            xml节点对象
	 * @return List<IParameterInfo> 该节点的参数信息
	 * 
	 * @throws SaturnComponentException
	 */
	@SuppressWarnings("unchecked")
	public static List<IParameterInfo> getParameterInfos(Bundle bundle,
			Element node) throws ClassNotFoundException {

		Element parameters = node.element(KEY_PARAMETER_LIST);

		if (parameters != null) {
			logger.debug("    load params:");
			parameters.elements(KEY_PARAMETER);
			List<Element> parameterElements = parameters
					.elements(KEY_PARAMETER);

			List<IParameterInfo> parameterInfos = new ArrayList<IParameterInfo>();

			for (Element parameterElement : parameterElements) {
				parameterInfos
						.add(createParameterInfo(bundle, parameterElement));
			}
			Collections.sort(parameterInfos);
			return parameterInfos;
		}
		return null;
	}

	/**
	 * 从xml配置文件中读取节点信息的抽象方法。
	 * <p>
	 * 不同结点的加载类需要分别实现该方法完成对指定结点的加载。 可以一次解析并加载一个配置文件中出现的所有相同类型的结点。
	 * <p>
	 * 
	 * @param bundle
	 * 
	 * @param root
	 *            xml配置文件的根结点对象。
	 * 
	 * @return List<INodeInfo> 返回解析的结点信息列表。
	 * 
	 * @throws SaturnComponentException
	 *             当解析某个结点出错时，该方法会抛出<code>SaturnComponentException</code>异常。
	 *             并停止对该配置文件的解析。
	 * 
	 */
	// TODO:参数bundle没有用上
	// TODO:多种异常类型
	public abstract List<INodeInfo> loadNode(Element root, Bundle bundle)
			throws SaturnComponentException;

	private static IParameterInfo createParameterInfo(Bundle bundle,
			Element parameter) throws ClassNotFoundException {

		String parameterClass = parameter.attributeValue(
				KEY_PARAMETER_CLASS_TYPE).trim();

		Class<?> parameterType = LoaderUtils.loadClass(bundle, parameterClass);
		int scope = IParameterInfo.SCOPE_LOGIC;

		try {
			scope = Integer
					.parseInt(parameter.elementText(KEY_PARAMETER_SCOPE));

		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
		String id = parameter.attributeValue(KEY_PARAMETER_ID).trim();
		String name = parameter.attributeValue(KEY_PARAMETER_NAME).trim();
		String passingType = parameter.attributeValue(
				KEY_PARAMETER_PASSING_TYPE).trim();

		String valueKey = parameter.elementTextTrim(KEY_PARAMETER_VALUE_KEY);
		String description = parameter
				.elementTextTrim(KEY_PARAMETER_DECRRIPTION);

		Element validates = parameter.element(KEY_PARAMETER_VALIDATEUSE);
		IValidateUseInfo validateUseInfo = ComponentFactory.getValidateUseInfo(
				bundle, validates);

		logger.debug("      load parameter id = \"" + id + ", name = \"" + name
				+ ", parameterType = \"" + parameterClass
				+ ", passingType = \"" + passingType + ", valueKey = \""
				+ valueKey + ", description = \"" + description
				+ ", scope = \"" + scope);

		return new SaturnParameterInfo(id, name, parameterType, passingType,
				valueKey, description, scope, validateUseInfo);
	}
}
